Skip to content

Implement Write for Cursor<W: AsMut<[u8]>> - #160960

Open
bushrat011899 wants to merge 1 commit into
rust-lang:mainfrom
bushrat011899:core_io_cursor_write_rewrite
Open

Implement Write for Cursor<W: AsMut<[u8]>>#160960
bushrat011899 wants to merge 1 commit into
rust-lang:mainfrom
bushrat011899:core_io_cursor_write_rewrite

Conversation

@bushrat011899

@bushrat011899 bushrat011899 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Change WriteThroughCursor into a specialization which allows Vec and &mut Vec to extend their allocation for writing. This makes discoverability of the Write implementation better.

ACP: rust-lang/libs-team#853
Tracking Issue: #154046
Follow Up To: #160952 & #158537

Description

Currently, Write is implemented for Cursor<W>, where W is one of:

  • &mut [u8]
  • for<const N: usize> [u8; N]
  • for<A: Allocator> Box<[u8], A>
  • for<A: Allocator> Vec<u8, A>
  • for<A: Allocator> &mut Vec<u8, A>

When moving Write into core::io, it was noted here that the documentation of Cursor would be degraded due to the introduction of WriteThroughCursor, an indirection trait to allow Cursor and Write in core, while Box and Vec exist in alloc.

To resolve this documentation regression, and add additional functionality as well, I'm proposing we instead implement Write for Cursor<W> where W: AsMut<[u8]>. All 5 of the original types above implement AsMut<[u8]>, so we'll correctly document the breadth of support.

However, for Vec and &mut Vec, I use specialization to allow their implementation to extend, rather than only writing to the existing slice. While this still uses an indirection trait (SpecCursorWrite), but now this is purely for specialization, and therefore doesn't need to be documented publicly.

I'm opening a PR directly as a reference point, but I suspect this will need an ACP since this changes the public API.


Notes

  • No AI tooling of any kind was used during the creation of this PR.

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 12, 2026
@rustbot rustbot added the T-libs Relevant to the library team, which will review and decide on the PR/issue. label Aug 12, 2026
@rustbot

rustbot commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

r? @Mark-Simulacrum

rustbot has assigned @Mark-Simulacrum.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: libs
  • libs expanded to 12 candidates
  • Random selection from JohnTitor, Mark-Simulacrum, clarfonthey, nia-e

@rust-bors

This comment has been minimized.

Change `WriteThroughCursor` into a specialization which allows `Vec` and `&mut Vec` to extend their allocation for writing. This makes discoverability of the `Write` implementation better.
@bushrat011899
bushrat011899 force-pushed the core_io_cursor_write_rewrite branch from 517f9a5 to 8142083 Compare August 12, 2026 22:07
@rustbot

rustbot commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Mark-Simulacrum

Copy link
Copy Markdown
Member

However, for Vec and &mut Vec, I use specialization to allow their implementation to extend

I haven't looked at the implementation yet, but I'm dubious on this being a good idea. Specialization used for performance seems OK, but exposing additional properties in the implementation seems pretty unfortunate.

Is the only reason to use specialization to avoid a publicly visible additional bound? Can we directly implement with the coherence bypassing attribute?

@bushrat011899

Copy link
Copy Markdown
Contributor Author

Is the only reason to use specialization to avoid a publicly visible additional bound?

Yeah the goal is to avoid exposing the current WriteThroughCursor trait, since it's just there to allow implementing a trait incoherently and not intended for the public to implement.

Can we directly implement with the coherence bypassing attribute?

I wasn't aware of any attribute that could allow an incoherent trait implementation. I'd be happy to use it if you could point me in the right direction?

@Mark-Simulacrum

Copy link
Copy Markdown
Member

Hm, maybe we don't have that capability today. rustc_allow_incoherent_impl gives me an error saying it can't be applied to trait impls (https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=6d5f1ffe3e8de8312cf273eca7274e3c). Poking around Zulip it sounds like it's not something easily extendable to traits (#t-types > rustc_allow_incoherent_impl @ 💬).

I guess WriteThroughCursor is not public, so users actually have no way to find these impls whatsoever today? That does seem unfortunate... maybe making it public (but unstable) for now would help mitigate that?

Do I understand correctly that with this PR, the rustdoc on Cursor and Write will show impl<W: AsMut<[u8]>> Write for Cursor<W> { ... }? I'm wondering how horrible it would be to have that impl under cfg(doc), and without cfg(doc) have the WriteThroughCursor story. AFAICT, there's not actually a regression in terms of what exists for doc tests and such under that scheme, right?

@bushrat011899

Copy link
Copy Markdown
Contributor Author

I guess WriteThroughCursor is not public, so users actually have no way to find these impls whatsoever today? That does seem unfortunate... maybe making it public (but unstable) for now would help mitigate that?

Yeah that's an issue introduced early in the core_io implementation cycle that was considered temporarily acceptable. Another annoyance here is that even if that trait was public, the documentation for Cursor will show some Write implementations, while the rest will be a click away in the documentation of that trait. It could be mitigated by just moving all implementations to that trait though.

Do I understand correctly that with this PR, the rustdoc on Cursor and Write will show impl<W: AsMut<[u8]>> Write for Cursor<W> { ... }?

Correct.

I'm wondering how horrible it would be to have that impl under cfg(doc), and without cfg(doc) have the WriteThroughCursor story. AFAICT, there's not actually a regression in terms of what exists for doc tests and such under that scheme, right?

I'm not against that. There'd still need to be some changes to how the trait is implemented since, today, it's only actually implemented for 5 types (slices, boxed slices, and Vec, etc.). This PR currently proposes expanding that to all AsMut<[u8]> types which better aligns with how the other IO traits are implemented for Cursor anyway.

@Mark-Simulacrum

Copy link
Copy Markdown
Member

Hm, that seems right. I guess we would still need specialization even with a custom trait (rather than AsMut)? Part of why I'm worried about that approach is it probably locks us out of nicely exposing the additional feature set to ecosystem types that support adding capacity (e.g., Bytes) - right?

I think there's no way to have impls for both impl AsMut and impl AsMut + Extend (or similar) without specialization :(

Everything here also needs to be insta-stable, right? That also seems unfortunate.

@bushrat011899

Copy link
Copy Markdown
Contributor Author

Hm, that seems right. I guess we would still need specialization even with a custom trait (rather than AsMut)? Part of why I'm worried about that approach is it probably locks us out of nicely exposing the additional feature set to ecosystem types that support adding capacity (e.g., Bytes) - right?

Another option, that I also see as having drawbacks, is marking Cursor as fundamental (like Box) which would allow external crates to implement traits for types wrapped by Cursor<T>. I see that as worse, since Cursor just doesn't feel "fundamental" in the same way Box, pointers, etc. are.

I think there's no way to have impls for both impl AsMut and impl AsMut + Extend (or similar) without specialization

Actually to add insult to injury, Extend isn't enough, because &mut Vec does not implement Extend, but Cursor<&mut Vec<u8>> does implement Write. So still more adjustments required. But I do agree that's the effect we'd like to have hear.

Everything here also needs to be insta-stable, right? That also seems unfortunate.

I believe so, since this is effectively a restructuring of existing stable implementations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants